package com.gome.boot.config.elasticsearch;

import com.gome.boot.common.util.CommonUtils;
import com.gome.boot.common.util.StringToUtils;
import com.gome.boot.config.elasticsearch.cluster.IndexConfig;
import com.gome.boot.config.elasticsearch.cluster.IndexTypeConfig;
import org.elasticsearch.common.collect.MapBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.util.ClassUtils;

import java.text.MessageFormat;
import java.util.Map;

/**
 * 基础索引配置.
 * <br/>应用各索引配置继承后进行实现.
 *
 * @author baoxiufeng
 */
public abstract class BaseIndexConfig {

    protected static final String DEFAULT_INDEX_ID_FIELD_NAME = "id";
    private static final String DEFAULT_INDEX_TYPE = "default";
    private static final String KEY_ES_INDEX_SHARDS = "es.{0}.index.number_of_shards";
    private static final String KEY_ES_NDEX_REPLICAS = "es.{0}.index.number_of_replicas";
    private static final String KEY_ES_INDEX_REFRESH_INTERVAL = "es.{0}.index.refresh_interval";
    private static final String KEY_ES_INDEX_STORE_TYPE = "es.{0}.index.store_type";
    private static final String KEY_ES_INDEX_TYPES = "es.{0}.index.types";
    private static final String KEY_ES_INDEX_MULTI = "es.{0}.index.multi";
    private static final String KEY_ES_INDEX_ALIAS = "es.{0}.index.alias";

    @Autowired
    protected Environment env;

    /**
     * 构建默认类型的索引配置.
     *
     * @return 索引配置
     */
    protected Map<String, String> buildIndexSettings() {
        return buildIndexSettings(null);
    }

    /**
     * 构建索引所有类型集合.
     *
     * @return 索引所有类型集合
     */
    protected Map<Class, IndexTypeConfig> buildIndexTypeMap() {
        return buildIndexTypeMap(null);
    }

    /**
     * 构建默认类型索引配置.
     *
     * @return 索引配置
     */
    protected IndexConfig buildIndexConfig() {
        return buildIndexConfig(null);
    }

    /**
     * 构建指定类型的索引配置.
     *
     * @param type 类型
     * @return 索引配置
     */
    protected Map<String, String> buildIndexSettings(String type) {
        if (CommonUtils.isEmpty(type)) {
            type = DEFAULT_INDEX_TYPE;
        }
        MapBuilder<String, String> builder = new MapBuilder<String, String>();
        builder.put("index.number_of_shards", env.getProperty(MessageFormat.format(KEY_ES_INDEX_SHARDS, type), "5"));
        builder.put("index.number_of_replicas", env.getProperty(MessageFormat.format(KEY_ES_NDEX_REPLICAS, type), "1"));
        builder.put("index.refresh_interval", env.getProperty(MessageFormat.format(KEY_ES_INDEX_REFRESH_INTERVAL, type), "1s"));
        builder.put("index.store.type", env.getProperty(MessageFormat.format(KEY_ES_INDEX_STORE_TYPE, type), "fs"));
        return builder.map();
    }

    /**
     * 构建索引所有类型集合.
     *
     * @param type 类型
     * @return 索引所有类型集合
     */
    protected Map<Class, IndexTypeConfig> buildIndexTypeMap(String type) {
        if (CommonUtils.isEmpty(type)) {
            type = DEFAULT_INDEX_TYPE;
        }
        Map<String, String> map = StringToUtils.stringToMap(env.getRequiredProperty(MessageFormat.format(KEY_ES_INDEX_TYPES, type)));
        MapBuilder<Class, IndexTypeConfig> builder = new MapBuilder<Class, IndexTypeConfig>();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            try {
                Class<?> forName = ClassUtils.forName(entry.getValue(), null);
                builder.put(forName, new IndexTypeConfig(entry.getKey(), DEFAULT_INDEX_ID_FIELD_NAME));
            } catch (Throwable t) {
                ;
            }
        }
        return builder.map();
    }

    /**
     * 构建指定类型索引配置.
     *
     * @param type 类型
     * @return 索引配置
     */
    protected IndexConfig buildIndexConfig(String type) {
        if (CommonUtils.isEmpty(type)) {
            type = DEFAULT_INDEX_TYPE;
        }
        IndexConfig config = new IndexConfig();
        config.setIndexAlias(env.getRequiredProperty(MessageFormat.format(KEY_ES_INDEX_ALIAS, type)));
        config.setMultiIndex(env.getProperty(MessageFormat.format(KEY_ES_INDEX_MULTI, type), Boolean.class, true));
        return config;
    }
}
